import React, { useState, useMemo, useCallback, useEffect } from "react";
import { Card, Button, Row, Col } from "antd";
import { Common, Validate } from "UtilsCommon";
import { Icon } from 'Configs';
import PropertyItem from "./propertyItem";
import Base from './base';

const setValue = (dataList, setDataList) => {
    dataList = dataList || [];
    setDataList(dataList);
};

const getPrimaryKey = (property) => {
    return property.entity ? property.entity.primaryKey : property.primaryKey || 'id';
};

const add = (data, property, dataList, setDataList) => {
    const primaryKey = getPrimaryKey(property);
    data[primaryKey] = data[primaryKey] || Common.createGuid();

    let blExists = false;
    const list = [];

    for (let i = 0; i < dataList.length; i++) {
        if (dataList[i][primaryKey] === data[primaryKey] || (property.keyName && dataList[i][property.keyName] === data[property.keyName])) blExists = true;
        else list.push(dataList[i]);
    }

    if (blExists) return;
    else list.push(data);

    setValue(list, setDataList);
};

const addSelectRows = (pageAxis, property, dataList, setDataList) => {
    if (property.selectRowsEventActionName) {
        pageAxis.invokeEventAction(property.selectRowsEventActionName, { pageAxis, property, dataList, setDataList });
    }
    else if (property.selectRowsEventAction) {
        pageAxis.invokeEventAction2(property.selectRowsEventAction, { pageAxis, property, dataList, setDataList });
    }
};

const update = (data, property, dataList, setDataList) => {
    const primaryKey = getPrimaryKey(property);
    const id = data[primaryKey];
    const editData = Common.arrayFirst(dataList, (f) => Common.isEquals(f[primaryKey], id, true));
    if (editData !== null) {
        for (const key in data) editData[key] = data[key];

        setValue(dataList.map(m => m), setDataList);
    }
};

const remove = (id, property, dataList, setDataList) => {
    const primaryKey = getPrimaryKey(property);
    setValue(dataList.filter(f => !Common.isEquals(f[primaryKey], id, true)), setDataList);
};

const validateValue = (validateName, v, p) => {
    if (!Validate[validateName]) return "";

    let msg = Validate[validateName](v, p.label);
    if (msg === true) msg = "";
    else if (p.validateTipMessage) msg = p.validateTipMessage;

    return msg;
};

const judgeNullable = (value, property, rowsColsProperties) => {
    const { nullTipMessage } = property;
    if (value.length === 0 && !property.isRowNullable) return nullTipMessage;

    let msg = ""; let v = null; let p = null;

    for (let i = 0; i < rowsColsProperties.length; i++) {
        p = rowsColsProperties[i];
        if (!p.getValue || !p.isEdit) continue;
        v = p.getValue();
        if (!p.isNullable && p.type === "Select" && Common.isNullOrEmpty(v)) {
            msg = p.nullTipMessage || "请选择" + p.label + "！";
            break;
        }
        else if (!p.isNullable && Common.isNullOrEmpty(v)) {
            msg = p.nullTipMessage || p.label + "不能为空！";
            break;
        }
        else if (!Common.isNullOrEmpty(v) && p.validateNames) {
            for (let i = 0; i < p.validateNames.length; i++) {
                msg = validateValue(p.validateNames[i], v, p);
                if (Common.isNullOrEmpty(msg)) break;
            };

            if (!Common.isNullOrEmpty(msg)) break;
        }
    }

    return msg;
};

const assignProperty = (p, data, view, controlProperties, rowsColsProperties) => {
    const primaryKey = getPrimaryKey(view);
    const id = data[primaryKey];
    const id2 = p.id + id;

    if (!controlProperties[id]) controlProperties[id] = {};
    const itemProperties = controlProperties[id];

    const propertyName = p.propertyName || p.name;
    const expandProperty = data[propertyName + "_ExpandProperty"] || {};

    if (itemProperties[id2]) p = itemProperties[id2];
    else {
        p = Object.assign(p, expandProperty, { value: data[propertyName] });
        itemProperties[id2] = p;
    }
    p.id = id2;
    p.dataId = id;
    p.data = data;
    p.isBind = true;

    rowsColsProperties.push(p);

    return p;
};

const renderItemProperty = (p, data, property, pageId, controlProperties, rowsColsProperties) => {
    p = assignProperty(p, data, property, controlProperties, rowsColsProperties);
    if (p.isSpanText) return <span key={p.id}>{data[p.name]}</span>;

    return <PropertyItem property={p} key={p.id} view={property} pageId={pageId} />;
};

const renderRowCols = (data, property, pageId, controlProperties, rowsColsProperties) => {
    return property.properties.map(m => <Col span={m.span} key={m.id}>{renderItemProperty(m, data, property, pageId, controlProperties, rowsColsProperties)}</Col>);
};

const rendDataItem = (data, property, pageId, pageAxis, controlProperties, rowsColsProperties) => {
    const primaryKey = getPrimaryKey(property);
    const id = data[primaryKey] || Common.createGuid();
    data[primaryKey] = id;
    pageAxis.rowViews = pageAxis.rowViews || {};
    let view = pageAxis.rowViews[id];
    if (!view) { view = Common.clone(property); pageAxis.rowViews[id] = view; }

    const fn = pageAxis.getFunction(property.fnSetProperties);
    if (fn) fn({ data, view });

    return (
        <Row gutter={6} key={data[primaryKey]} style={{ padding: "8px 8px", borderBottom: "1px solid #e8e8e8" }}>
            {renderRowCols(data, view, pageId, controlProperties, rowsColsProperties)}
        </Row>
    );
};

const renderHeaderCols = (property) => {
    return property.properties.map(m => <Col span={m.span} key={m.name}>{m.header || m.label}</Col>);
};

const renderHeaderRowsCols = (property) => {
    return (
        <Row gutter={6} className={"rowHeader"}>
            {renderHeaderCols(property)}
        </Row>
    );
};

const renderRightButton = (property, pageAxis, pageId, addRow, selectRows) => {
    if (property.rightProperty) return <PropertyItem property={property.rightProperty} view={property} pageId={pageId} />;
    if (property.isSelect) return <Button onClick={selectRows} icon={<Icon type='select' />} type="primary">选择</Button>;
    if (property.isAdd === false) return null;

    if (property.addEventAction && !property.addRowEvent) {
        property.addRowEvent = () => {
            pageAxis.invokeEventAction2(property.addEventAction, { pageAxis, property: {}, complexDataGrid: property });
        };
    }

    const addRowEvent = property.addRowEvent || addRow;

    return <Button onClick={addRowEvent} icon={<Icon type='plus' />} type="primary">添加</Button>;
};

const rendDataItemList = (dataList, property, pageId, pageAxis, controlProperties, rowsColsProperties) => {
    return dataList.map((m) => rendDataItem(m, property, pageId, pageAxis, controlProperties, rowsColsProperties));
};

const renderTitle = (property, pageId) => {
    return <PropertyItem property={property.titleProperty} view={property} pageId={pageId} />;
};

export default React.memo((props) => {
    const { property, pageAxis, pageId } = Base.getProps(props);
    const [isVisible, setIsVisible] = useState(property.isVisible !== false);
    const [dataList, setDataList] = useState(property.value || property.defaultValue || []);

    const controlProperties = useMemo(() => ({}), []);
    const rowsColsProperties = [];

    useEffect(() => {
        if (property.setDataLoad) property.setDataLoad(dataList);
    }, [dataList, property]);

    const addRow = useCallback(() => {
        const defaultRowData = property.defaultRowData || {};
        add({ ...defaultRowData }, property, dataList, setDataList);
    }, [dataList, property, setDataList]);

    const selectRows = useCallback(() => {
        addSelectRows(pageAxis, property, dataList, setDataList);
    }, [pageAxis, dataList, property, setDataList]);

    property.setIsVisible = (v) => setIsVisible(v);
    property.add = (v) => add(v, property, dataList, setDataList);
    property.update = (v) => update(v, property, dataList, setDataList);
    property.remove = (v) => remove(v, property, dataList, setDataList);
    property.setValue = (v) => setValue(v, setDataList);
    property.getValue = () => dataList;
    property.refresh = () => setDataList(dataList.map(m => m));
    property.judgeNullable = (v) => judgeNullable(v, property, rowsColsProperties);

    if (!isVisible) return null;

    return (
        <Card title={property.titleProperty ? renderTitle(property, pageId) : property.title} headStyle={{ fontWeight: 700 }} extra={renderRightButton(property, pageAxis, pageId, addRow, selectRows)}
            bordered={false} style={{ marginBottom: 16 }} bodyStyle={{ padding: 0, paddingTop: 4 }}>
            {renderHeaderRowsCols(property)}
            {rendDataItemList(dataList, property, pageId, pageAxis, controlProperties, rowsColsProperties)}
        </Card>
    );
});